import hashlib
import os
import struct
import threading
from socket import *


class Client:
    main_path = os.getcwd()

    def __init__(self, ip, port):
        self.client: socket = None
        self.ip = ip
        self.port = port
        self.client_init()

    def client_init(self):
        while True:
            init()
            self.tcp_connect()
            global uesr_name,password
            # flag为1，说明要注册
            if flag=='1':
                self.send_train('000',self.client)#000是注册的暗号
                self.send_train(user_name,self.client)
                self.send_train(password,self.client)
                data=self.revc_train(self.client).decode('utf8')
                print(data)
                if data=='用户名已存在':
                    self.client.close()
                    continue
                else:
                    user_name=input('请输入用户名（大于四位）：')
                    password=input('请输入密码：')
                    self.client.close()
                    self.tcp_connect()
            # 发送用户名和密码，验证是否正确
            self.send_train(user_name.encode('utf8'),self.client)
            self.send_train(password.encode('utf8'),self.client)
            data=self.revc_train(self.client).decode('utf8')
            if data=='登陆成功':
                self.token=self.revc_train(self.client).decode('utf8')
                self.send_command()
                break
            else:
                continue

    def tcp_connect(self):
        self.client = socket(AF_INET, SOCK_STREAM)
        self.client.connect((self.ip, self.port))

    # def client_init(self):
    #     while True:
    #         self.tcp_connect()
    #         self.send_command()

    def send_train(self, send_bytes, client):
        # send火车，就是把某个字节流内容以火车形式发过去
        # 每次发东西，先拿到头部，再拿到内容（不管文件名还是文件内容）
        train_head_bytes = struct.pack('I', len(send_bytes))
        client.send(train_head_bytes + send_bytes)

    def revc_train(self, client):
        # recv火车，就是把火车recv的内容返回出去
        # 先接到火车头，再根据火车头的长度收到火车内容
        train_head_bytes = self.client.recv(4)
        train_head = struct.unpack('I', train_head_bytes)
        return client.recv(train_head[0])

    def send_command(self):
        # 发送各种命令给服务器
        while True:
            # 读取命令，并发送给服务器端，用开火车的方式发送(发字节流）
            command = input()
            # self.send_train(command.encode('utf8')),把上传下载和lscd分开发送命令后，就不能统一写在这了，要分别写send_train
            # 切片，得字符串的前两个
            if command[:2] == 'ls':
                self.do_ls()
            elif command[:2] == 'cd':
                self.do_cd()
            elif command[:3] == 'pwd':
                self.do_pwd()
            elif command[:2] == 'rm':
                self.do_rm(command)
            elif command[:4] == 'gets':
                # 上传下载时要启动子线程做，需要重新connect，并发送token
                client = socket(AF_INET, SOCK_STREAM)
                client.connect((self.ip, self.port))
                self.send_train(self.token, client)
                self.send_train(command, client)
                t_gets = threading.Thread(target=self.do_gets, args=(command, client))
                t_gets.start()  # start是启动子线程
                # self.do_gets(command)
            elif command[:4] == 'puts':
                # 上传下载时要启动子线程做，需要重新connect，并发送token
                file_name=command.split()[1]
                if file_name in os.listdir():
                    client=socket(AF_INET,SOCK_STREAM)
                    client.connect((self.ip,self.port))
                    self.send_train(self.token,client)
                    self.send_train(command,client)
                    t_puts=threading.Thread(target=self.do_puts,args=(file_name,client))
                    t_puts.start()
                else:
                    print('您要上传的文件不存在')
                # self.do_puts(command)
            else:
                print('wrong command')

    def do_ls(self):
        # 当前路径下的信息传输给客户端
        self.send_train('ls', self.client)
        data = self.revc_train(self.client).decode('utf8')
        print(data)

    def do_cd(self, command):
        self.send_train(command, self.client)
        print(self.revc_train(self.client).decode('utf8'))

    def do_pwd(self):
        self.send_train('pwd', self.client)
        print(self.revc_train(self.client).decode('utf8'))

    def do_rm(self, command):
        self.send_train(command, self.client)
        print(self.revc_train(self.client).decode('utf8'))

    # 上传用到了秒传
    def do_puts(self, file_name,client):
        # 发送md5值
        md5_num = md5(file_name)
        # print(md5_num)
        self.send_train(md5_num,client)
        # print('发送md5值')
        flag1 = struct.unpack('I', client.recv(4))[0]
        if flag1:
            flag2 = struct.unpack('I', client.recv(4))[0]
            # print('收到flag：%d'%flag2)
            if flag2:
                file_size = os.stat(file_name).st_size
                client.send(struct.pack('I', file_size))
                # 循环发送文件内容
                total = 0
                f = open(file_name, 'rb')
                while True:
                    file_content = f.read(10000)
                    if file_content:
                        client.send(file_content)
                        total += len(file_content)
                    else:
                        f.close()
                        break
            print('上传完毕')
            client.close()
        else:
            print('该目录下已经存在名为：%s的文件' % file_name)

    def do_gets(self, command, client):
        # 接收一个标记位，判断服务器是否存在该文件
        flag = struct.unpack('I', client.recv(4))[0]
        if flag:
            print('开始接收')
            file_name = command.split()[1]
            # 接收文件大小
            file_size_bytes = client.recv(4)
            file_size = struct.unpack('I', file_size_bytes)[0]
            f = open(file_name, 'wb')
            # 循环接收文件内容
            total = 0
            while True:
                file_content = client.recv(10000)
                f.write(file_content)
                total += len(file_content)
                # 文件接收完毕跳出循环
                if total == file_size:
                    f.close()
                    print('接收完毕')
                    break
        else:
            print('文件不存在')
        client.close()


# md5算法
def md5(file_name):
    f = open(file_name, 'rb')
    f_md5 = hashlib.md5()
    f_md5.update(f.read())
    f.close()
    return (f_md5.hexdigest())

def init():
    global user_name, password, flag
    flag = input('登陆请按 0 注册请按 1')
    while True:
        user_name=input('请输入用户名（大于四位）：')
        if len(user_name)<4:
            continue
        password=input('请输入密码：')
        break


if __name__ == '__main__':
    client = Client('192.168.124.1', 2000)
    # client.client_init()
    # client.tcp_connect()
    # client.send_command()
